local Player = class("Player")
local InputConst = require("const.InputConst")
local Vector3 = require("utils.Vector3")
local UIUtils = require("utils.UIUtil")
local MathUtils = require("utils.MathUtils")
local GameConst = require("const.GameConst")

local ROTATE_SPEED = 200
local UPDATE_POS_TIME = 1
local rotSpeed = 20

function Player:start()
    self.forward = Vector3.new(0, 0, 0)
    self.lerp = 0
    self.animator = self.gameObject:GetComponent(typeof(CS.UnityEngine.Animator))
    self.controller = self.gameObject:GetComponent(typeof(CS.UnityEngine.CharacterController))
    self._renders = self.gameObject:GetComponentsInChildren(typeof(Unity.Renderer))
    self.mainCamera = UIUtils.getMainCamera()
    self:calcSubPosition()
    local pPositin = self.transform.position
    local cPosition = self.mainCamera.transform.position
    self.distance = 20
    self.isRotaing = false
    self.moveDirection = Vector3.new(0, 0, 0)
    self._updatePosDt = UPDATE_POS_TIME
    self._lastMoveDirection = Vector3.new(0, 0, 0)
    self._textName.text = G_UserData:getBase():getName()
    self:changePlayMat()
end

function Player:changePlayMat()
    local material = G_ResourceManager:loadMaterial("PlayerMat")
    local len = self._renders.Length
    for i = 0, len - 1, 1 do
        local render = self._renders[i]
        local Length = render.materials.Length
        local array = {}
        for j = 1, Length, 1 do
            local tex = render.materials[j - 1]:GetTexture("_MainTex")
            local mat = CS.UnityEngine.Material(material)
            mat:CopyPropertiesFromMaterial(material)
            mat.shader = material.shader
            mat:SetTexture("_MainTex", tex)
            array[j] = mat
        end
        render.materials = array
    end
end

function Player:updateDt(dt, horizontal, vertical)
    if not self.enabled then
        return
    end
    if not self:move(horizontal, vertical, dt) then
        self:_updatePos(dt)
    end
end

function Player:_updatePos(dt)
    self._updatePosDt = self._updatePosDt + dt
    if self._updatePosDt >= UPDATE_POS_TIME then
        self._updatePosDt = 0
        G_SignalManager:dispatch(SignalConst.EVENT_PLAYER_UPDATE_POS, self.transform.forward, self.transform.position)
    end
end

function Player:onTriggerEnter(other)
end

function Player:cameraDirectionProcess(inputDirection, upAxis)
    local mainCamera = self.mainCamera
    local quat = CS.UnityEngine.Quaternion.FromToRotation(mainCamera.transform.up, upAxis)
    local cameraForwardDirection = quat * mainCamera.transform.forward
    local moveDirection =
        CS.UnityEngine.Quaternion.LookRotation(cameraForwardDirection, upAxis) * inputDirection.normalized
    return moveDirection
end

function Player:rotateProcess(moveDirection, upAxis, dt)
    local moveDirection = CS.UnityEngine.Vector3.ProjectOnPlane(moveDirection, upAxis)
    local playerLookAtQuat = CS.UnityEngine.Quaternion.LookRotation(moveDirection, upAxis)
    self.transform.rotation = CS.UnityEngine.Quaternion.Lerp(self.transform.rotation, playerLookAtQuat, rotSpeed * dt)
end

function Player:move(horizontal, vertical, dt)
    local axisH = horizontal --G_Input.GetAxis("Horizontal")
    local axisV = vertical --G_Input.GetAxis("Vertical")
    local ismoving = self.animator:GetBool("isMoving")
    local isInTransition = self.animator:IsInTransition(0)
    local isCan = not isInTransition
    local isUpdate = false
    if (math.abs(axisH) > 0.1 or math.abs(axisV) > 0.1) and isCan then
        local vec = Vector3.new(axisH, 0, axisV)
        local dir = self:cameraDirectionProcess(vec, Vector3.new(0, 1, 0))
        local velocity = dir * GameConst.MOVE_SPEED
        self.moveDirection.x = velocity.x
        self.moveDirection.z = velocity.z
        self:rotateProcess(dir, Vector3.new(0, 1, 0), dt)
        if ismoving == false then
            self.animator:SetBool("isMoving", true)
        end
    else
        self.moveDirection.x = 0
        self.moveDirection.z = 0
        if ismoving == true then
            self.animator:SetBool("isMoving", false)
        end
    end
    if self.moveDirection.x ~= self._lastMoveDirection.x or self.moveDirection.z ~= self._lastMoveDirection.z then
        isUpdate = true
    end
    if self.controller.isGrounded then -- 跳跃
        if G_Input.GetKeyDown(CS.UnityEngine.KeyCode.Space) then
            self.moveDirection.y = GameConst.JUMP_SPEED
            isUpdate = true
        end
    end
    if isUpdate then
        G_SignalManager:dispatch(
            SignalConst.EVENT_PLAYER_UPDATE_VEC,
            self.transform.forward,
            self.transform.position,
            self.moveDirection
        )
    end
    self.moveDirection.y = math.max(self.moveDirection.y - GameConst.GRAVITY * dt, -100)
    self.controller:Move(self.moveDirection * dt)
    self._lastMoveDirection.x = self.moveDirection.x
    self._lastMoveDirection.z = self.moveDirection.z
    return isUpdate
end

function Player:resetMoveDirection()
    self.moveDirection.x = 0
    self.moveDirection.y = 0
    self.moveDirection.z = 0
    G_SignalManager:dispatch(
        SignalConst.EVENT_PLAYER_UPDATE_VEC,
        self.transform.forward,
        self.transform.position,
        self.moveDirection
    )
end

function Player:calcSubPosition()
    local pPositin = self.transform.position
    local cPosition = self.mainCamera.transform.position
    self.subPosition = cPosition - pPositin
end

function Player:rotateCamera()
    if G_Input.GetMouseButton(1) then
        self.isRotaing = true
    else
        self.isRotaing = false
    end
    if self.isRotaing then
        local originalPosition = self.mainCamera.transform.position
        local originalRotation = self.mainCamera.transform.rotation
        self.mainCamera.transform:RotateAround(
            self.transform.position,
            self.transform.up,
            G_Input.GetAxis("Mouse X") * ROTATE_SPEED * G_Time.deltaTime
        )
        self.mainCamera.transform:RotateAround(
            self.transform.position,
            self.mainCamera.transform.right,
            -G_Input.GetAxis("Mouse Y") * ROTATE_SPEED * G_Time.deltaTime
        ) --//会影响position和rotation
        local x = self.mainCamera.transform.eulerAngles.x --//读取Rotation的x值
        if x < 10 or x > 70 then
            self.mainCamera.transform.position = originalPosition
            self.mainCamera.transform.rotation = originalRotation
        end
        self:calcSubPosition()
    end
end

function Player:rotateCameraUp(axisX)
    local center = self.transform.position
    local rotate = axisX * ROTATE_SPEED
    rotate = MathUtils.clamp(rotate, -ROTATE_SPEED, ROTATE_SPEED)
    self:rotateAround(center, Vector3.up, rotate)
    self:calcSubPosition()
end

function Player:rotateCameraRight(axisY)
    local rotate = axisY * ROTATE_SPEED
    local center = self.transform.position
    local pos = self.mainCamera.transform.localToWorldMatrix:MultiplyPoint(Vector3.new(-1, 0, 0))
    local dir = pos - self.mainCamera.transform.position
    self.mainCamera.transform:RotateAround(center, dir.normalized, rotate)
    self:calcSubPosition()
end

function Player:rotateAround(center, axis, angle)
    local pos = self.mainCamera.transform.position
    local rot = CS.UnityEngine.Quaternion.AngleAxis(angle, axis)
    local dir = pos - center --//计算从圆心指向摄像头的朝向向量
    dir = rot * dir --//旋转此向量
    --//移动摄像机位置
    local newPos = center + dir
    self.mainCamera.transform.position = newPos
    self.mainCamera.transform:LookAt(center)
end

function Player:updateCameraPosition()
    local pPositin = self.transform.position
    local newPosition = pPositin + self.subPosition.normalized * self.distance
    self.mainCamera.transform.position = newPosition
    self.lerp = self.lerp + G_Time.deltaTime
end

function Player:onDestroy()
end

return Player
